import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error
from sklearn.ensemble import RandomForestRegressor
from sklearn.feature_selection import RFE
from lime.lime_tabular import LimeTabularExplainer
import xgboost
from xgboost import XGBRegressor
raw_data = pd.read_csv("compas-scores-two-years.csv")
df = raw_data[["age", "c_charge_degree", "race", "age_cat", "score_text", "sex", "priors_count",
"days_b_screening_arrest", "decile_score", "is_recid",
"two_year_recid", "c_jail_in", "c_jail_out"]]
df = df[df["days_b_screening_arrest"] <= 30]
df = df[df["days_b_screening_arrest"] >= -30]
df = df[df["is_recid"] != -1]
df = df[df["c_charge_degree"] != "0"]
df = df[df["score_text"] != 'N/A']
df["prob_score"] = df.apply(lambda row: row['decile_score']/10, axis=1)
#df["length_of_stay"] = pd.to_numeric(pd.to_datetime(df["c_jail_out"]) - pd.to_datetime(df["c_jail_in"]))
df["length_of_stay"] = pd.to_datetime(df["c_jail_out"]) - pd.to_datetime(df["c_jail_in"])
df["length_of_stay_in_days"] = pd.to_numeric(df["length_of_stay"].dt.days)
df["factor_recid"], _ = pd.factorize(df["is_recid"])
df["factor_recid_two_years"], _ = pd.factorize(df["two_year_recid"])
df["factor_race"], _ = pd.factorize(df["race"])
df["factor_gender"], _ = pd.factorize(df["sex"])
df["factor_crime"], _ = pd.factorize(df["c_charge_degree"])
df["factor_score"], _ = pd.factorize(df["score_text"])
df["numeric_jail_in"] = pd.to_datetime(df["c_jail_in"])
#df["factor_age"],_ = pd.factorize(df["age_cat"])
df.shape
regression_model_df = df[["age",
"factor_recid",
"factor_recid_two_years",
"factor_race",
"factor_gender",
"factor_crime",
"length_of_stay_in_days",
"priors_count"]]
label = df["prob_score"]
X_train, X_test, y_train, y_test = train_test_split(regression_model_df, label, test_size=0.2, random_state=0)
def classifier(model):
model.fit(X_train, y_train)
pred = model.predict(X_test)
mse, mae, rscore = mean_squared_error(y_test, pred), mean_absolute_error(y_test, pred), r2_score(y_test, pred)
print(f"MSE: {mse}, MAE: {mae}, R^2 score: {rscore}")
return model, pred
model_rf, pred_rf = classifier(RandomForestRegressor(n_estimators = 100, random_state = 0))
lime_explainer = LimeTabularExplainer(X_train,
mode='regression',
feature_names=X_train.columns,
discretize_continuous=False,
verbose=True)
lime_explainer.explain_instance(X_test.iloc[10], model_rf.predict, num_features=6,num_samples=1000).show_in_notebook(show_table=True)
Powyższy wykres przedstawia wyjaśnienie predykcji dla pojedynczej obserwacji o numerze 10. Dla tej obserwacji istotne są zmienne takie jak: wiek (age), liczba dokonanych wcześniej przestępstw (priors_count) oraz ilość pełnych dób spędzonych w więzieniu (length_of_stay_in_days), przy czym wiek wpływa na zmiejszenie p-stwa, że ta osoba zostanie recydywistą.
lime_explainer.explain_instance(X_test.iloc[10], model_rf.predict, num_features=6,num_samples=500).show_in_notebook(show_table=True)
lime_explainer.explain_instance(X_test.iloc[10], model_rf.predict, num_features=6,num_samples=2000).show_in_notebook(show_table=True)
Powyższe 2 wykresy przedstawiają wyjaśnienie predykcji dla tej samej obserwacji o numerze 10, ale ze zmienionym parametrem odpowiadającym za liczbę obserwacji wziętych do wyznaczenia Lime (num_samples) kolejno na: 500 i 2000. Jak widać wyjaśnienia dla tej obserwacji nie zmieniły się ze wględu na zmianę tego parametru, co może świadczyć o stabilności wyjaśnień.
lime_explainer.explain_instance(X_test.iloc[998], model_rf.predict, num_features=6,num_samples=2000).show_in_notebook(show_table=True)
Powyższy wykres przedstawia wyjaśnienie predykcji dla pojedynczej obserwacji o numerze 998. Dla tej obserwacji istotne są zmienne takie jak: wiek (age), liczba dokonanych wcześniej przestępstw (priors_count), ilość pełnych dób spędzonych w więzieniu (length_of_stay_in_days), oraz raca (factor_race) przy czym wiek oraz rasa (factor_race=Hispanic) wpływa na zmiejszenie p-stwa, że ta osoba zostanie recydywistą.
lime_explainer.explain_instance(X_test.iloc[501], model_rf.predict, num_features=6,num_samples=2000).show_in_notebook(show_table=True)
Powyższy wykres przedstawia wyjaśnienie predykcji dla pojedynczej obserwacji o numerze 501. W tym przypadku istotne są kolejno zmienne takie jak: liczba dokonanych wcześniej przestępstw (priors_count), wiek (age) oraz ilość pełnych dób spędzonych w więzieniu (length_of_stay_in_days), przy czym liczba dokonanych wcześniej przestępstw wpływa znacząco na zwiększenie p-stwa, że ta osoba zostanie recydywistą.
Warto zauważyć, że dla obserwacji 10 i 998, które są dosyć podobne, wyjaśnienia były bardzo zbliżone. Natomiast dla obserwacji 501, która miała na koncie sporą ilość dokonanych przestępstw, to wyjaśnienie nieco uległo zmianie, co również pokazuje stabilność wyjaśnień.
Powyższy wykres przedstawia wyjaśnienie predykcji dla pojedynczej obserwacji o numerze 15. Liczba dokonanych wcześniej przestępstw (priorscount), wiek (age) oraz długość pobytu w więzieniu (lengthofstay) zwiększają p-stwo bycia recydywistą, zaś zmienna dotycząca płci (factor_gender) nieco zmniejszają to p-stwo. Ostatecznie predykcja wynosi 0.839.
xgb = XGBRegressor(objective='reg:logistic')
xgb.fit(X_train.values, y_train.values)
y_pred_train = xgb.predict(X_train.values)
y_pred_test = xgb.predict(X_test.values)
mse, mae, rscore = mean_squared_error(y_test, y_pred_test), mean_absolute_error(y_test, y_pred_test), r2_score(y_test, y_pred_test)
print(f"MSE: {mse}, MAE: {mae}, R^2 score: {rscore}")
lime_explainer.explain_instance(X_test.iloc[501], xgb.predict, num_features=6,num_samples=2000).show_in_notebook(show_table=True)
Powyżej przedstawiam obserwację o numerze 501, która ma wysoką wartość predykcji w przypadku obu modeli. Wyjaśnienie wartości tej predykcji w przypadku modelu Random Forest i XGBoost różni się nieznacznie. W wyjaśnieniu modelu XGBoost pojawiają się zmienne factor_gender (płeć), która nie pojawiły się w wyjaśnieniu predykcji modelu Random Forest dla tej obserwacji. Z kolei w modelu Random Forest istotna (choć w niewielkim stopniu) była zmienna factor_race (dot. rasy).